home *** CD-ROM | disk | FTP | other *** search
- /*
- * WinClipboard Win32 Windoze Copy&Paste Plug-in
- * Copyright (C) 1999 Hans Breuer
- * Hans Breuer, Hans@Breuer.org
- * 08/07/99
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Based on (at least) the following plug-ins:
- * Header
- * WinSnap
- *
- * Any suggestions, bug-reports or patches are welcome.
- */
-
- #include "config.h"
-
- #include <windows.h>
- #include <stdlib.h>
-
- #include <libgimp/gimp.h>
-
- #include "libgimp/stdplugins-intl.h"
-
-
- /* History:
- *
- * 08/07/99 Implementation and release.
- * 08/10/99 Big speed increase by using gimp_tile_cache_size()
- * Thanks to Kevin Turner's documentation at:
- * http://www.poboxes.com/kevint/gimp/doc/plugin-doc-2.1.html
- *
- * TODO (maybe):
- *
- * - Support for 4,2,1 bit bitmaps
- * - Unsupported formats could be delegated to GIMP Loader (e.g. wmf)
- * - ...
- */
-
- /* How many steps the progress control should do
- */
- #define PROGRESS_STEPS 25
- #define StepProgress(one,all) \
- (0 == (one % ((all / PROGRESS_STEPS)+1)))
-
- /* FIXME: I'll use -1 as IMAGE_NONE. Is it correct ???
- */
- #define IMAGE_NONE -1
-
- /* Declare some local functions.
- */
- static void query (void);
- static void run (gchar *name,
- gint nparams,
- GimpParam *param,
- gint *nreturn_vals,
- GimpParam **return_vals);
-
- /* Plugin function prototypes
- */
- static int CB_CopyImage (gboolean interactive,
- gint32 image_ID,
- gint32 drawable_ID);
-
- static int CB_PasteImage (gboolean interactive,
- gint32 image_ID,
- gint32 drawable_ID);
-
-
- GimpPlugInInfo PLUG_IN_INFO =
- {
- NULL, /* init_proc */
- NULL, /* quit_proc */
- query, /* query_proc */
- run, /* run_proc */
- };
-
-
- MAIN ()
-
- static void
- query ()
- {
- static GimpParamDef copy_args[] =
- {
- { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
- { GIMP_PDB_IMAGE, "image", "Input image" },
- { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" }
- };
- static gint ncopy_args = sizeof (copy_args) / sizeof (copy_args[0]);
-
- gimp_install_procedure ("plug_in_clipboard_copy",
- "copy image to clipboard",
- "Copies the active drawable to the clipboard.",
- "Hans Breuer",
- "Hans Breuer",
- "1999",
- N_("<Image>/Edit/Copy to Clipboard"),
- "INDEXED*, RGB*",
- GIMP_PLUGIN,
- ncopy_args, 0,
- copy_args, NULL);
-
- gimp_install_procedure ("plug_in_clipboard_paste",
- "paste image from clipboard",
- "Paste image from clipboard into active image.",
- "Hans Breuer",
- "Hans Breuer",
- "1999",
- N_("<Image>/Edit/Paste from Clipboard"),
- "INDEXED*, RGB*",
- GIMP_PLUGIN,
- ncopy_args, 0,
- copy_args, NULL);
-
- gimp_install_procedure ("extension_clipboard_paste",
- "Get image from clipboard",
- "Get an image from the Windows clipboard, creating a new image",
- "Hans Breuer",
- "Hans Breuer",
- "1999",
- N_("<Toolbox>/File/Acquire/From Clipboard"),
- "",
- GIMP_EXTENSION,
- ncopy_args, 0,
- copy_args, NULL);
-
- }
-
- static void
- run (gchar *name,
- gint nparams,
- GimpParam *param,
- gint *nreturn_vals,
- GimpParam **return_vals)
- {
- static GimpParam values[2];
- GimpRunModeType run_mode;
-
- run_mode = param[0].data.d_int32;
-
- *nreturn_vals = 1;
- *return_vals = values;
- values[0].type = GIMP_PDB_STATUS;
- values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
-
- INIT_I18N();
-
- if (strcmp (name, "plug_in_clipboard_copy") == 0)
- {
- *nreturn_vals = 1;
- if (CB_CopyImage (GIMP_RUN_INTERACTIVE==run_mode,
- param[1].data.d_int32,
- param[2].data.d_int32))
- values[0].data.d_status = GIMP_PDB_SUCCESS;
- else
- values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
- }
- else if (strcmp (name, "plug_in_clipboard_paste") == 0)
- {
- *nreturn_vals = 1;
- if (CB_PasteImage (GIMP_RUN_INTERACTIVE==run_mode,
- param[1].data.d_int32,
- param[2].data.d_int32))
- values[0].data.d_status = GIMP_PDB_SUCCESS;
- else
- values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
- }
- else if (strcmp (name, "extension_clipboard_paste") == 0)
- {
- *nreturn_vals = 1;
- if (CB_PasteImage (GIMP_RUN_INTERACTIVE==run_mode,
- IMAGE_NONE,
- IMAGE_NONE))
- values[0].data.d_status = GIMP_PDB_SUCCESS;
- else
- values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
- }
- }
-
- /* Plugin Function implementation
- */
- static int
- CB_CopyImage (gboolean interactive,
- gint32 image_ID,
- gint32 drawable_ID)
- {
- GimpDrawable *drawable;
- GimpImageType drawable_type;
- GimpPixelRgn pixel_rgn;
- gchar *sStatus = NULL;
-
- int nSizeDIB=0;
- int nSizePal=0;
- int nSizeLine=0; /* DIB lines are 32 bit aligned */
-
- HANDLE hDIB;
- BOOL bRet;
-
- drawable = gimp_drawable_get (drawable_ID);
- drawable_type = gimp_drawable_type (drawable_ID);
- gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
-
- /* allocate room for DIB */
- if (GIMP_INDEXED_IMAGE == drawable_type)
- {
- nSizeLine = ((drawable->width-1)/4+1)*4;
- nSizeDIB = sizeof(RGBQUAD) * 256 /* always full color map size */
- + nSizeLine * drawable->height
- + sizeof (BITMAPINFOHEADER);
- }
- else
- {
- nSizeLine = ((drawable->width*3-1)/4+1)*4;
- nSizeDIB = nSizeLine * drawable->height
- + sizeof (BITMAPINFOHEADER);
- }
-
- hDIB = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, nSizeDIB);
- if (NULL == hDIB)
- {
- g_message ("Failed to allocate DIB");
- bRet = FALSE;
- }
-
- /* fill header info */
- if (bRet)
- {
- BITMAPINFOHEADER *pInfo;
-
- bRet = FALSE;
- pInfo = GlobalLock (hDIB);
- if (pInfo)
- {
- pInfo->biSize = sizeof(BITMAPINFOHEADER);
- pInfo->biWidth = drawable->width;
- pInfo->biHeight = drawable->height;
- pInfo->biPlanes = 1;
- pInfo->biBitCount = (GIMP_INDEXED_IMAGE == drawable_type ? 8 : 24);
- pInfo->biCompression = BI_RGB; /* none */
- pInfo->biSizeImage = 0; /* not calculated/needed */
- pInfo->biXPelsPerMeter =
- pInfo->biYPelsPerMeter = 0;
- /* color map size */
- pInfo->biClrUsed = (GIMP_INDEXED_IMAGE == drawable_type ? 256 : 0);
- pInfo->biClrImportant = 0; /* all */
-
- GlobalUnlock (hDIB);
- bRet = TRUE;
- } /* (pInfo) */
- else
- g_message("Failed to lock DIB Header");
- }
-
- /* fill color map */
- if (bRet && (GIMP_INDEXED_IMAGE == drawable_type))
- {
- char *pBmp;
-
- bRet = FALSE;
- pBmp = GlobalLock (hDIB);
- if (pBmp)
- {
- RGBQUAD *pPal;
- int nColors;
- unsigned char *cmap;
- pPal = (RGBQUAD*)(pBmp + sizeof(BITMAPINFOHEADER));
- nSizePal = sizeof(RGBQUAD) * 256;
-
- /* get the gimp colormap */
- cmap = gimp_image_get_cmap (image_ID, &nColors);
-
- if (cmap)
- {
- int i;
- for (i = 0; (i < 256) && (i < nColors); i++)
- {
- pPal[i].rgbReserved = 0; /* is this alpha? */
- pPal[i].rgbRed = cmap[3*i];
- pPal[i].rgbGreen = cmap[3*i+1];
- pPal[i].rgbBlue = cmap[3*i+2];
- }
-
- g_free(cmap);
- bRet = TRUE;
- } /* (cmap) */
- else
- g_message ("Can't get color map");
- GlobalUnlock (hDIB);
- } /* (pBmp) */
- else
- g_message ("Failed to lock DIB Palette");
- } /* indexed */
-
- /* following the slow part ... */
- if (interactive)
- gimp_progress_init (_("Copying ..."));
-
- /* speed it up with: */
- gimp_tile_cache_size (drawable->width * gimp_tile_height () * drawable->bpp);
-
- /* copy data to DIB */
- if (bRet)
- {
- unsigned char *pData;
-
- bRet = FALSE;
- pData = GlobalLock (hDIB);
-
- if (pData)
- {
- unsigned char *pLine;
-
- /* calculate real offset */
- pData += (sizeof(BITMAPINFOHEADER) + nSizePal);
-
- pLine = g_new (guchar, drawable->width * drawable->bpp);
-
- if (GIMP_INDEXED_IMAGE == drawable_type)
- {
- int x, y;
- for (y = 0; y < drawable->height; y++)
- {
- if ((interactive) && (StepProgress(y,drawable->height)))
- gimp_progress_update ((double)y / drawable->height);
-
- gimp_pixel_rgn_get_row (&pixel_rgn, pLine, 0,
- drawable->height-y-1, /* invert it */
- drawable->width);
- for (x = 0; x < drawable->width; x++)
- pData[x+y*nSizeLine] = pLine[x*drawable->bpp];
- }
- }
- else
- {
- int x, y;
- for (y = 0; y < drawable->height; y++)
- {
- if ((interactive) && (StepProgress(y,drawable->height)))
- gimp_progress_update ((double)y / drawable->height);
-
- gimp_pixel_rgn_get_row (&pixel_rgn, pLine, 0,
- drawable->height-y-1, /* invert it */
- drawable->width);
- for (x = 0; x < drawable->width; x++)
- {
- /* RGBQUAD: blue, green, red, reserved */
- pData[x*3+y*nSizeLine] = pLine[x*drawable->bpp+2]; /* blue */
- pData[x*3+y*nSizeLine+1] = pLine[x*drawable->bpp+1]; /* green */
- pData[x*3+y*nSizeLine+2] = pLine[x*drawable->bpp]; /* red */
- /*pData[x+y*drawable->width*3+3] = 0;*/ /* reserved */
- }
- }
- }
-
- g_free (pLine);
- bRet = TRUE;
-
- GlobalUnlock (hDIB);
- } /* (pData) */
- else
- g_message("Failed to lock DIB Data");
- } /* copy data to DIB */
-
- /* copy DIB to ClipBoard */
- if (bRet)
- {
- if (!OpenClipboard (NULL))
- {
- g_message ("Cannot open the Clipboard!");
- bRet = FALSE;
- }
- else
- {
- if (bRet && !EmptyClipboard ())
- {
- g_message ("Cannot empty the Clipboard");
- bRet = FALSE;
- }
- if (bRet)
- {
- if (NULL != SetClipboardData (CF_DIB, hDIB))
- hDIB = NULL; /* data now owned by clipboard */
- else
- g_message ("Failed to set clipboard data ");
- }
-
- if (!CloseClipboard ())
- g_message ("Failed to close Clipboard");
- }
- }
- /* done */
- if (hDIB)
- GlobalFree(hDIB);
-
- gimp_drawable_detach (drawable);
-
- return bRet;
- } /* CB_CopyImage */
-
- static void
- decompose_mask (guint32 mask,
- gint *shift,
- gint *prec)
- {
- *shift = 0;
- *prec = 0;
-
- while (!(mask & 0x1))
- {
- (*shift)++;
- mask >>= 1;
- }
-
- while (mask & 0x1)
- {
- (*prec)++;
- mask >>= 1;
- }
- }
-
- static int
- CB_PasteImage (gboolean interactive,
- gint32 image_ID,
- gint32 drawable_ID)
- {
- UINT fmt;
- BOOL bRet=TRUE;
- HANDLE hDIB;
- BITMAPINFO *pInfo;
- gint32 nWidth = 0;
- gint32 nHeight = 0;
- gint32 nBitsPS = 0;
- gint32 nColors = 0;
- guint32 maskR;
- guint32 maskG;
- guint32 maskB;
- gint shiftR;
- gint shiftG;
- gint shiftB;
- gint precR;
- gint precG;
- gint precB;
- gint maxR;
- gint maxG;
- gint maxB;
-
- if (!OpenClipboard (NULL))
- {
- g_message("Failed to open clipboard");
- return FALSE;
- }
-
- fmt = EnumClipboardFormats (0);
- while ((CF_BITMAP != fmt) && (CF_DIB != fmt) && (0 != fmt))
- fmt = EnumClipboardFormats (fmt);
-
- if (0 == fmt)
- {
- g_message (_("Unsupported format or Clipboard empty!"));
- bRet = FALSE;
- }
-
- /* there is something supported */
- if (bRet)
- {
- hDIB = GetClipboardData (CF_DIB);
-
- if (NULL == hDIB)
- {
- g_message (_("Can't get Clipboard data."));
- bRet = FALSE;
- }
- }
-
- /* read header */
- if (bRet && hDIB)
- {
- pInfo = GlobalLock (hDIB);
- if (NULL == pInfo)
- {
- g_message ("Can't lock Clipboard data!");
- bRet = FALSE;
- }
-
- if (bRet && pInfo->bmiHeader.biCompression == BI_BITFIELDS)
- {
- maskR = ((DWORD *)pInfo->bmiColors)[0];
- maskG = ((DWORD *)pInfo->bmiColors)[1];
- maskB = ((DWORD *)pInfo->bmiColors)[2];
- decompose_mask (maskR, &shiftR, &precR);
- maxR = (1 << precR) - 1;
- decompose_mask (maskG, &shiftG, &precG);
- maxG = (1 << precG) - 1;
- decompose_mask (maskB, &shiftB, &precB);
- maxB = (1 << precB) - 1;
- }
-
- if ((bRet) &&
- ((pInfo->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)
- || (pInfo->bmiHeader.biCompression != BI_RGB
- && pInfo->bmiHeader.biCompression != BI_BITFIELDS))))
- {
- g_message ("Unsupported bitmap format (%d)!",
- pInfo->bmiHeader.biCompression);
- bRet = FALSE;
- }
-
- if (bRet && pInfo)
- {
- nWidth = pInfo->bmiHeader.biWidth;
- nHeight = pInfo->bmiHeader.biHeight;
- nBitsPS = pInfo->bmiHeader.biBitCount;
- nColors = pInfo->bmiHeader.biClrUsed;
- }
- }
-
- if ((0 != nWidth) && (0 != nHeight))
- {
- GimpDrawable *drawable;
- GimpPixelRgn pixel_rgn;
- guchar *pData;
- GimpParam *params;
- gint retval;
- gboolean bIsNewImage = TRUE;
- gint oldBPP = 0;
- guchar *pLine;
- RGBQUAD *pPal;
- const int nSizeLine = ((nWidth*(nBitsPS/8)-1)/4+1)*4;
-
- /* Check if clipboard data and existing image are compatible */
- if (IMAGE_NONE != drawable_ID)
- {
- drawable = gimp_drawable_get (drawable_ID);
- oldBPP = drawable->bpp;
- gimp_drawable_detach (drawable);
- }
-
- if ((IMAGE_NONE == image_ID)
- || (3 != oldBPP) || (24 != nBitsPS))
- {
- /* create new image */
- image_ID = gimp_image_new (nWidth, nHeight, nBitsPS <= 8 ? GIMP_INDEXED : GIMP_RGB);
- gimp_image_undo_disable(image_ID);
- drawable_ID = gimp_layer_new (image_ID, _("Background"), nWidth, nHeight,
- nBitsPS <= 8 ? GIMP_INDEXED_IMAGE : GIMP_RGB_IMAGE,
- 100, GIMP_NORMAL_MODE);
- }
- else
- {
- /* ??? gimp_convert_rgb (image_ID);
- */
- drawable_ID = gimp_layer_new (image_ID, _("Pasted"), nWidth, nHeight,
- nBitsPS <= 8 ? GIMP_INDEXED_IMAGE : GIMP_RGB_IMAGE,
- 100, GIMP_NORMAL_MODE);
- bIsNewImage = FALSE;
- }
-
- gimp_image_add_layer (image_ID, drawable_ID, -1);
- drawable = gimp_drawable_get (drawable_ID);
-
- gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
-
- /* following the slow part ... */
- if (interactive)
- gimp_progress_init (_("Pasting..."));
-
- /* adjust pointer */
- pPal = pInfo->bmiColors;
- if (pInfo->bmiHeader.biCompression == BI_BITFIELDS)
- pData = (guchar*)pPal + sizeof(DWORD) * 3;
- else
- pData = (guchar*)pPal + sizeof(RGBQUAD) * nColors;
-
- /* create palette */
- if (0 != nColors)
- {
- int c;
- guchar *cmap;
-
- cmap = g_new (guchar, nColors*3);
- for (c = 0; c < nColors; c++)
- {
- cmap[c*3] = pPal[c].rgbRed;
- cmap[c*3+1] = pPal[c].rgbGreen;
- cmap[c*3+2] = pPal[c].rgbBlue;
- }
- gimp_image_set_cmap (image_ID, cmap, nColors);
- g_free (cmap);
- }
-
- /* speed it up with: */
- gimp_tile_cache_size (drawable->width * gimp_tile_height () * drawable->bpp );
-
- /* change data format and copy data */
- if ((24 == nBitsPS && pInfo->bmiHeader.biCompression == BI_RGB)
- || (pInfo->bmiHeader.biCompression == BI_BITFIELDS))
- {
- int y;
- const int bps = nBitsPS / 8;
- pLine = g_new (guchar, drawable->width*drawable->bpp);
-
- for (y = 0; y < drawable->height; y++)
- {
- int x;
-
- if ((interactive) && (StepProgress (y, drawable->height)))
- gimp_progress_update ((double)y / drawable->height);
-
- if (pInfo->bmiHeader.biCompression == BI_RGB)
- for (x = 0; x < drawable->width; x++)
- {
- pLine[x*drawable->bpp] = pData[y*nSizeLine+x*bps+2];
- pLine[x*drawable->bpp+1] = pData[y*nSizeLine+x*bps+1];
- pLine[x*drawable->bpp+2] = pData[y*nSizeLine+x*bps];
- }
- else
- for (x = 0; x < drawable->width; x++)
- {
- guint dw;
-
- if (nBitsPS == 32)
- dw = *((DWORD *)(pData + y*nSizeLine + x*4));
- else
- dw = *((WORD *)(pData + y*nSizeLine + x*2));
- pLine[x*drawable->bpp] = (255 * ((dw & maskR) >> shiftR)) / maxR;
- pLine[x*drawable->bpp+1] = (255 * ((dw & maskG) >> shiftG)) / maxG;
- pLine[x*drawable->bpp+2] = (255 * ((dw & maskB) >> shiftB)) / maxB;
- }
-
- /* copy data to GIMP */
- gimp_pixel_rgn_set_rect (&pixel_rgn, pLine, 0, drawable->height-1-y, drawable->width, 1);
- }
- g_free (pLine);
- }
- else if (8 == nBitsPS)
- {
- int y;
- /* copy line by line */
- for (y = 0; y < drawable->height; y++)
- {
- if ((interactive) && (StepProgress (y, drawable->height)))
- gimp_progress_update ((double)y / drawable->height);
-
- pLine = pData + y*nSizeLine; /* adjust pointer */
- gimp_pixel_rgn_set_row (&pixel_rgn, pLine, 0, drawable->height-1-y, drawable->width);
- }
- }
- else
- {
- /* copy and shift bits */
- g_message ("%d bits per sample not yet supported!", nBitsPS);
- }
-
- gimp_drawable_flush (drawable);
- gimp_drawable_detach (drawable);
-
- /* Don't forget to display the new image! */
- if (bIsNewImage)
- gimp_display_new (image_ID);
- else
- {
- gimp_layer_set_visible (drawable_ID, TRUE);
- gimp_displays_flush ();
- }
- }
-
- /* done */
- /* clear clipboard? */
- if (NULL != hDIB)
- {
- GlobalUnlock (pInfo);
- GlobalFree (hDIB);
- }
-
- CloseClipboard ();
-
- /* shouldn't this be done by caller?? */
- gimp_image_undo_enable (image_ID);
-
- return bRet;
- } /* CB_PasteImage */
-